package com.yuxl.ai.spg.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.data.neo4j.core.ReactiveNeo4jClient;
import reactor.core.publisher.Mono;
import reactor.core.publisher.Flux;

import java.util.HashMap;
import java.util.Map;

@Service
public class AiSpgNeo4jService {
    private static final Logger log = LoggerFactory.getLogger(AiSpgNeo4jService.class);
    @Autowired
    private ReactiveNeo4jClient neo4jClient;

    public Mono<String> createEntity(Map<String, Object> entity) {
        // Cypher: CREATE (n:Entity $props) RETURN n.name AS name
        return neo4jClient.query("CREATE (n:Entity $props) RETURN n.name AS name")
                .in("mydb")
                .bind(entity).to("props")
                .fetch()
                .one()
                .map(map -> map.get("name").toString());
    }

    public Mono<String> createRelation(String from, String to, String relation) {
        // Cypher: MATCH (a:Entity {name: $from}), (b:Entity {name: $to}) MERGE (a)-[r:REL]->(b) RETURN type(r) AS rel
        String cypher = String.format(
                "MATCH (a:Entity {name: $from}), (b:Entity {name: $to}) MERGE (a)-[r:%s]->(b) RETURN type(r) AS rel",
                relation
        );
        return neo4jClient.query(cypher)
                .bind(from).to("from")
                .bind(to).to("to")
                .fetch()
                .one()
                .map(map -> map.get("rel").toString());
    }

    public Mono<Map<String, Object>> findEntity(String name) {
        // Cypher: MATCH (n:Entity {name: $name}) RETURN n
        return neo4jClient.query("MATCH (n:Entity {name: $name}) RETURN n")
                .bind(name).to("name")
                .fetch()
                .one()
                .map(map -> {
                    Object n = map.get("n");
                    if (n instanceof Map) {
                        return (Map<String, Object>) n;
                    } else {
                        Map<String, Object> result = new HashMap<>();
                        result.put("n", n);
                        return result;
                    }
                });
    }

    public Flux<Map<String, Object>> findAllEntities() {
        // Cypher: MATCH (n:Entity) RETURN n
        return neo4jClient.query("MATCH (n:Entity) RETURN n")
                .fetch()
                .all()
                .map(map -> {
                    Object n = map.get("n");
                    if (n instanceof Map) {
                        return (Map<String, Object>) n;
                    } else {
                        Map<String, Object> result = new HashMap<>();
                        result.put("n", n);
                        return result;
                    }
                });
    }

    /**
     * 创建新的 Neo4j 数据库（需要管理员权限）
     */
    public Mono<Boolean> createDatabase(String dbName) {
        // 只能在 system 数据库下执行 CREATE DATABASE
        return neo4jClient.query("CREATE DATABASE " + dbName)
                .in("system") // 必须在 system 库下执行
                .run()
                .map(result -> true)
                .onErrorResume(e -> {
                    log.error("创建数据库失败：{}", e.getMessage(), e);
                   return Mono.just(false);
                });
    }
}
